#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include "core/fid.h"

#define CAST(fid) ((char*)fid)

static int validFid(const FidPtr fid)
	{
	 int i=0;
	if(fid==NULL) return 0;
	while(isdigit(CAST(fid)[i]) && 0!=(fid[i]) && i< FID_MAX_LENGTH)
		{
		i++;
		}
	return i+1==FID_MAX_LENGTH?1:0;
	}

const ChromNamePtr FidGetChromosome(const FidPtr fid,long *position)
	{

	ChromNamePtr chr= NULL;
	char c[3]={CAST(fid)[3],CAST(fid)[4],0};
	assert(fid!=NULL);


	if(!validFid(fid))
		{
		chr = ChromNameGetById(ChrUndefined);
		}
	else
		{
		chr = ChromNameGetById((enum ChromName_E)(atoi(c[0] != '0' ? c: &c[1])) );
		}

	if(chr->id==ChrUndefined)
		{
		if(position!=NULL) *position=-1L;
		return chr;
		}
	if(position!=NULL)
		{
		int i = 6;
        	while(fid[i] == '0' && i < FID_MAX_LENGTH) i++;
        	if (isdigit(fid[i])) *position= atol(&fid[i]);
		}
	return chr;
	}

const OrganismPtr FidGetOrganism(const FidPtr fid)
	{
	char c[3]={CAST(fid)[1],CAST(fid)[2],0};
	if(!validFid(fid)) return OrganismGetById(UndefinedOrganism);

	OrganismPtr org=OrganismGetByOpCode((enum Organism_E)atoi(c[0]!='0'?c:&c[1]));
	return org;
	}


int FidPrintXML(FILE* out,const FidPtr fid)
	{
	long position=-1L;
	ChromNamePtr chr= FidGetChromosome(fid,&position);
	OrganismPtr org= FidGetOrganism(fid);
	if(!validFid(fid))
		{
		fprintf(out,"<invalid-fid>%s</invalid-fid>",CAST(fid));
		return 0;
		}

	fputs("<mapping>",out);
	if(org!=NULL) fprintf(out,"<organism taxid=\"%d\">%s</organism>",org->taxId,org->taxName);
	fprintf(out,"<chromosome id=\"%d\">%s</chromosome>",chr->id,chr->name);
	if(chr->id!= ChrUndefined) fprintf(out,"<position>%ld</position>",position);
	fputs("</mapping>",out);
	return 0;
	}

int FidPrintText(FILE* out,const FidPtr fid)
	{
	long position=-1L;

	ChromNamePtr chr= FidGetChromosome(fid,&position);
	OrganismPtr org= FidGetOrganism(fid);

	if(!validFid(fid))
			{
			fprintf(out,"invalid_fid:%s",CAST(fid));
			return 0;
			}
	fputs("(",out);
	fprintf(out,"fid:%s|",CAST(fid));
	if(org!=NULL) fprintf(out,"taxId=%d|taxName=\"%s\"|",org->taxId,org->taxName);
	fprintf(out,"chrom:\"%s\"|id:%d",chr->name,chr->id);
	if(chr->id!= ChrUndefined) fprintf(out,"|pos:%ld",position);
	fputs(")",out);
	return 0;
	}

int FidPrintJSON(FILE* out,const FidPtr fid)
	{
	long position=-1L;

	if(!validFid(fid))
			{
			fprintf(out,"invalid_fid:\"%s\"",CAST(fid));
			return 0;
			}

	fputs("{",out);
	ChromNamePtr chr= FidGetChromosome(fid,&position);
	OrganismPtr org= FidGetOrganism(fid);
	if(org!=NULL) fprintf(out,"organism:{taxid:%d,taxName:\"%s\"},",org->taxId,org->taxName);
	fprintf(out,"chrom{name:\"%s\",id:%d}",chr->name,chr->id);
	if(chr->id!= ChrUndefined) fprintf(out,",position:%ld",position);
	fputs("}",out);
	return 0;
	}

int FidPrintFormatted(FILE* out,const FidPtr ptr,enum Format fmt)
	{
	int ret=0;
	switch(fmt)
		{
		case FORMAT_TEXT : ret= FidPrintText(out,ptr); break;
		case FORMAT_XML : ret= FidPrintXML(out,ptr); break;
		case FORMAT_JSON : ret= FidPrintJSON(out,ptr); break;
		default:return -1;
		}
	return ret;
	}
